feat: regional-plot backend (cis_associations, ld_r2, JSON endpoints)#25
feat: regional-plot backend (cis_associations, ld_r2, JSON endpoints)#25boxiangliu wants to merge 3 commits into
Conversation
Backend half of the LocuszoomZ-style regional plot (design in #23). No UI yet — the Plotly frontend waits for Liu Fei's design sign-off. - repository.py: cis_associations() (all cis variants for a gene in one tissue), ld_r2() (r² to a lead from the 1000G LD tables; symmetric-pair UNION, rsID<->int bridge, NA/non-rs skipping), tissues_with_signal() (drives the future body map); _ld_table() with chrom/pop whitelists. - viz.py: frozen LocusZoom LD color scheme (r2_color / ld_legend) + neg_log10_p. - web.py: GET /api/gene/{key}/regional (variants + r² to default lead) and GET /api/ld (r² map for click-to-recolor). - 100% coverage, mypy strict. Verified live: TP53 -> 5442 variants + r² in ~0.5s. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Closes #27. Wires the #25 backend into the gene page as a LocusZoom-style Plotly plot, styled to Liu Fei's mockup (#23). - gene.html: blue/slate palette; tissue + LD-population selectors; a Plotly scattergl of position vs −log10(p) colored by r² (first paint from /api/gene/{key}/regional); click a point to re-pick the lead (/api/ld, client-side re-color); genome-wide-significance line; LD legend + caveat. - viz.py: lead marker -> orange #f97316 (per Liu Fei), was purple. - web.py: gene page passes the tissue list to the selector. - Template-render tested; 100% coverage. Verified live: /gene/TP53 renders the plot UI with 25 real tissues. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
feat: regional plot frontend — Plotly Locus View on the gene page (#27)
gaojunbin
left a comment
There was a problem hiding this comment.
no LD data (grey) is misleading — the LD tables floor r² at 0.2
On real data (TP53 × Skin, EUR), 5427 of 5442 points render grey #AAAAAA "no LD data". It seems the tkg_p3v5a_ld_* tables only store pairs with r² ≥ 0.2.
So grey conflates two different things: truly absent from the panel vs r² < 0.2 (weak LD, just not stored). A standard LocusZoom colors the latter dark blue/indigo — here they look like missing data. As a side effect, the 0.0–0.2 indigo bin in viz.py (#463699) is effectively unreachable.
Suggestion (non-blocking): either relabel the legend to "r² < 0.2 or no LD data", or keep grey but note the 0.2 storage floor in the caption. Worth confirming whether the 0.2 cutoff is intentional in the LD-generation step.
What
The backend for the LocusZoom-style regional plot (design: #23 /
docs/design/gene-page-visualizations.md). No UI — the Plotly frontend waits for the design sign-off.repository.py:cis_associations(all cis variants for a gene × tissue),ld_r2(r² to a lead from the 1000G LD tables — symmetric-pair UNION, rsID↔int bridge, skips non-rs/NA),tissues_with_signal(for the future body map);_ld_tablewith chrom/population whitelists.viz.py: frozen LocusZoom LD color scheme +−log₁₀(p)helper.web.py:GET /api/gene/{key}/regionalandGET /api/ld.Why
Pure data plumbing, no design decisions → safe to build while Liu Fei reviews the design. When she signs off, wiring the Plotly frontend is quick.
How it was tested
ruff/mypy --strict/pytestgreen; 100% coverage; hermetic (fake repo + fake DB connection). Verified live (read-only): TP53 → 5,442 variants with r² to the lead in ~0.5s; the/api/gene/.../regionalendpoint returns correctly (LD partners coloured, non-partners grey = no-LD).Note re the LD index (issue for @gaojunbin)
The design flagged a covering index as a perf need, but the live LD query ran in 0.2s without it — so it's a nice-to-have, not urgent.
Checklist